Skip to content

Conversation

@macropay-solutions
Copy link
Owner

@macropay-solutions macropay-solutions commented Nov 1, 2025

This will reduce the number of calls to getDirty during save and also the sync/merge of casted attributes into objects when getAttributeFromArray is called.

Also it will reduce the operation number for update.

Also it will prevent changes in created,updated,saved events from getting into $original without being saved into DB

The only changes that could generate a breaking change are the new properties from HasAttributes trait

    /**
     * Temporary cache to avoid multiple getDirty calls generating multiple set calls for
     * sync/merge casted attributes to objects to persist the possible changes made to those objects
     */
    protected ?array $tmpDirtyIfAttributesAreSyncedFromCashedCasts = null;

    /**
     * Temporary original cache to prevent changes in created,updated,saved events from getting
     * into $original without being saved into DB
     */
    protected ?array $tmpOriginalBeforeAfterEvents = null;

related laravel/framework#57627
related discussion laravel/framework#31778

This will allow lock for updates in the model:

    /**
     * Prevent updates
     * Note that relations can be loaded and updated during the lock
     */
    public function lockUpdates(bool $checkDirty = true): bool
    {
        if (
            !$this->exists
            || $this->tmpDirtyIfAttributesAreSyncedFromCashedCasts !== null
            || ($checkDirty && $this->isDirty())
        ) {
            return false;
        }

        $this->tmpDirtyIfAttributesAreSyncedFromCashedCasts = [];

        return true;
    }

    /**
     * Unlock updates
     *
     * To reset the model's $attributes and get the changes from dirty applied during the lock use:
     *
     * if ($this->unlockUpdates()) {
     *  $dirty = $this->getDirty();
     *  $this->attributes = $this->original;
     *  $this->classCastCache = [];
     *  $this->attributeCastCache = [];
     * }
     *
     * Note that relations can be loaded during the lock
     */
    public function unlockUpdates(): bool
    {
        if ($this->hasUnlockedUpdates()) {
            return false;
        }

        $this->tmpDirtyIfAttributesAreSyncedFromCashedCasts = null;

        return true;
    }

    public function hasUnlockedUpdates(): bool
    {
        return $this->tmpDirtyIfAttributesAreSyncedFromCashedCasts !== [];
    }

@macropay-solutions macropay-solutions changed the title POC for https://github.com/laravel/framework/discussions/31778 POC for https://github.com/laravel/framework/discussions/31778 excesive set calls for casts Nov 1, 2025
Copy link

@churkindmitry churkindmitry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Pantea Marius-ciclistu added 5 commits November 3, 2025 16:35
…model and revert reduce even more the number of set calls during insert also
…model and revert reduce even more the number of set calls during insert also
…model and revert reduce even more the number of set calls during insert also
…model and revert reduce even more the number of set calls during insert also
@macropay-solutions
Copy link
Owner Author

Pantea Marius-ciclistu added 8 commits November 4, 2025 20:48
$model = User::query()->firstOrFail();
$carbon = $model->date_time_carbon_casted;
$carbon->addDay();
echo $model->col_with_get_mutator_that_depends_on_date_time_carbon_casted;
// would print 'value date time' without the added day before this commit
…d that got into $original but not in db
…cause isDirty will sync/merge the cast cached objects
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants